package qscript;

import java.util.List;

import org.qscript.Complex;
import org.qscript.Result;
import org.qscript.Script;
import org.qscript.Solver;
import org.qscript.Solver$;
import org.qscript.Token;
import org.qscript.errors.EvaluationException;
import org.qscript.errors.SyntaxException;
import org.qscript.events.TraceEvent;
import org.qscript.events.EvaluationErrorEvent;
import org.qscript.events.HaltExecutionEvent;
import org.qscript.events.OutputEvent;
import org.qscript.events.SyntaxErrorEvent;
import org.qscript.events.ResumeEvent;
import org.qscript.events.ScriptEvent;
import org.qscript.events.ScriptFinishedEvent;
import org.qscript.events.StoreUpdateEvent;
import org.qscript.events.WaitEvent;
import org.qscript.eventsonfire.EventHandler;


public class Test {

	public String a0 = " $x = 0.7 ; $s = 'peter k ' + 'def' + ''; println($s); $y = sin($x); END(1234)";
	public String a1 = " $x = 0.7 ; $s = 'peter k ' + 'def' + ''; $y = sin($x);  END(1234)";
	public String a2 = " $x = 8; IF($x > 2); $x = 0.7; ENDIF; $s = 'abc' + 'def' + ''; println($s); $y = sin($x); ";
	public String a8 = " x = 8; WHILE(x >= 0); x = x -1; WEND; END(x); ";
	public String a9 = " x = 8; WHILE(x >= 0); y = x; WHILE(y >= 0); println(x + ' ' + y); y = y - 1; WEND; x = x -1; WEND; END(x); ";
	public String[] b9 = { " x = 8", " WHILE(x >= 0)", " y = x", " WHILE(y >= 0)", " println(x + ' ' + y)", " y = y - 1", " WEND", "x = x -1", " WEND", "END(x); " };

	public String v1 = "n = vX( V(101,202,303) ); END(n)";
	// Intro page
	public String ws_1a = "nX = 2 + 2; println(nX)";
	public String ws_1b = "sqrt(5^2 + 12^2)";
	public String ws_1c = "$x=2; println($x + ' cubed is ' + $x^3)";

	// Modes page
	public String ws_2a = "$x=2; println($x + ' cubed is ' + $x^3)";

	public String[] t0 = {"maxN = max(2, 4)", "prinln(maxN + ' cubed is ' + maxN^3)" };

	String[] brot = new String[] {
			"# Calculate the number of iterations",
			"# before we leave the Mandelbrot set",
			"z = complex(0,0); n = 0; ",
			"WHILE(n < 16 && mag(z) < 2)",
			"  z = z * z + c; n = n + 1",
			"WEND",
			"END(n)"
	};

	String exp0 = "2 * atan2(y,max(x, 0)) > 3 && (0.5 > sin(2+z) / 5)";
	
	public void go_brot(){
		Script script = new Script(brot);
		script.storeVariable("c", new Complex(-0.9, 1.1));
	
		Result r = Solver.evaluate(script);
		System.out.println(getAnswer(r));

	}
	public void run(){

		//		test_unary_plus_minus("22 % +7");
		//		test_unary_plus_minus("22 % -7");

		//		errorReporting("maxN = max(2, 4 + 9); println(maxN + ' cubed is ' + maxN^3)");

		//		errorReporting("x = 0.7 ; y = 3  (4 + 3); z = cos(x + y); ");

		test_A(exp0);
		//test_B(m8);

		//		errorReporting(m0);
		//		errorReporting(m1);
		//		errorReporting(m2);
		//		errorReporting(m7);
		//		errorReporting(m8);
		//		errorReporting(m9);

	}

	public void errorReporting(String line){
		System.out.println("#################################################");
		System.out.println("## Using    Script.parse");
		System.out.println(line);
		System.out.println("0         1         2         3         4         5         6         7         8");
		Script s = new Script(line);
		s.parse();

	}

	public void errorReporting(String[] lines){
		System.out.println("#################################################");
		System.out.println("## Using    Script.parse");
		for(String line : lines)
			System.out.println(line);
		System.out.println("0         1         2         3         4         5         6         7         8");
		Script s = new Script(lines);
		s.parse();

	}

	

	public void test_unary_plus_minus(String line){
		System.out.println("#################################################");
		System.out.println("## Using    Solver.evaluate");
		System.out.println(line);
		Script script = new Script(line);

		Result r = Solver.evaluate(script);
		System.out.println(getAnswer(r));

	}

	public void test_A(String line){
		Result r;
		System.out.println("#################################################");
		System.out.println("## Using    Solver.evaluate");
		System.out.println(line);
		Script script = new Script(line);
		script.addListener(this);
		System.out.println("---------------------------------------");
		System.out.println("Non threading version");
		r = Solver.evaluate(script);
		System.out.println(getAnswer(r));
//		System.out.println("\nThreaded version");
//		r = Solver$.evaluate(script).get();
//		System.out.println(getAnswer(r));
//		System.out.println("-------------------------------------------------");
	}

	public void test_B(String[] lines){
		Result r;
		System.out.println("#################################################");
		System.out.println("## Using    Solver.evaluate");
		for(String line : lines)
			System.out.println(line);	
		Script script = new Script(lines);
		script.addListener(this);
		System.out.println("---------------------------------------");
		System.out.println("Non threading version");
		r = Solver.evaluate(script);
		System.out.println(getAnswer(r));
		System.out.println("\nThreaded version");
		Solver$ solver = Solver$.evaluate(script);
		while(!solver.isDone());
		r = solver.get();		
		System.out.println(getAnswer(r));
		System.out.println("-------------------------------------------------");
	}

	public void test_C(String[] lines){
		Result r = null;
		Script script;
		System.out.println("#################################################");
		System.out.println("## Using    Solver.parse / Solver.evaluate");
		for(String line : lines)
			System.out.println(line);
		script = new Script(lines);
		script.addListener(this);
		System.out.println("---------------------------------------");
		System.out.println("Non threading version");
		script.parse();
		if(script.isParsed())
			r = script.evaluate();
		System.out.println(getAnswer(r));
		System.out.println("\nThreaded version");
		script = new Script(lines);
		try {
			script.parse_();
			r = script.evaluate_();
		} catch (EvaluationException e) {
			System.out.println("Handle evaluation error");
		} catch (SyntaxException e) {
			System.out.println("Handle syntax error");
		}
		System.out.println(getAnswer(r));
		System.out.println("-------------------------------------------------");
	}

	String getAnswer(Result r){
		if(r == null)
			return ":: Error occured during execution";
		else
			return ":: " +  (r.isValid() ? r.answer.toString() : r.errorMessage);
	}

	String[] m0 = new String[] {
			" $n1 = 6; $n2 = 1; $result = 'z' ",
			"WHILE($n1 < 9)",
			"  $n1 = $n1 + 1; $result = $result + $n1",
			"  $n2 = 1",
			"  REPEAT",
			"    $result = $result + $n2; $n2 = $n2 + 1",	
			"  UNTIL($n2 >= 3)",
			"  $result = $result + '?'",
			"WEND",
			"END($n1 + $n2)"
	};

	String[] m1 = new String[] {
			"$n1 = 6",
			"WHILE($n1 < 9)",
			"  $n1 = $n1 + 1",
			"  $n2 = 1",
			"  REPEAT",
			"    $result = $n2; $n2 = $n2 + 1",	
			"  UNTIL($n2 >= 3)",
			"  $result = $result + '?'",
			"WEND",
			"END($n1 + $n2)"
	};


	String[] m2 = new String[] {
			"$n1 = 21",
			"IF($n1 > 10)",
			"	 $n2 = 1",
			"  IF($n1 > 20)",
			"    $n2 = 2",
			"  ENDIF",
			"ELSE",
			"  IF($n1 < 10)",
			"    $n2 = 3",
			"  ELSE",
			"    $n2 = 4",
			"  ENDIF",
			"ENDIF",
			"END($n1 + $n2)"
	};


	String[] m3 = new String[] {
			"$n1 = 4; $n2 = 1; $result = '' ",
			"WHILE($n1 <= 9)",
			"  $result = $result + $n1",
			"  IF($n1 > 7)",
			"    $n2 = 0",
			"    REPEAT",
			"      $result = $result + $n2; $n2 = $n2 + 1",		
			"    UNTIL($n2 >= 3)",
			"  ELSE",
			"    $n2 = 4",
			"    REPEAT",
			"      $result = $result + $n2; $n2 = $n2 - 1",		
			"    UNTIL($n2 <= 2)",
			"  ENDIF",
			"  $result = $result + '?'",
			"  $n1 = $n1 + 1",
			"WEND",
			"END($result)"
	};

	String[] m7 = { 
			"$maxPrime = 20", 
			"println('Prime numbers < ' + $maxPrime)", 
			"$lastPrime = 2", 
			"$n = 3", 
			"REPEAT", 
			"  $rootN = int(sqrt($n))", 
			"  $notPrime = false;", 
			"  $i = 3", 
			"  WHILE($i <= $rootN && NOT($notPrime))", 
			"    $notPrime = ($n % $i == 0)", 
			"    $i = $i + 1", 
			"  WEND", 
			"  IF($notPrime == false)", 
			"    $lastPrime = $n", 
			"    println($n)", 
			"  ENDIF", 
			"  $n = $n + 2", 
			"UNTIL($n >= $maxPrime)", 
			"END('Finished')"
	};

	String[] m8 = { 
			"maxPrime = 20", 
			"# Calculate the primes upto 20", 
			"println('Prime numbers < ' + maxPrime)", 
			"lastPrime = 2", 
			"n = 3", 
			"REPEAT", 
			"  log10rootN = int(sqrt(n))", 
			"  IFnotPrime = false;", 
			"  i = 3", 
			"  WHILE(i <= log10rootN && NOT(IFnotPrime))", 
			"    IFnotPrime = (n % i == 0)", 
			"    i = i + 1", 
			"  WEND", 
			"  IF(IFnotPrime == false) # Found prime", 
			"    lastPrime = n", 
			"    println(n)", 
			"  ENDIF", 
			"  n = n + 2", 
			"UNTIL(n >= maxPrime)", 
			"println(runtime())",
			"END('Finished')"
	};

	String[] m9 = new String[]{
			"$maxPrime = 20",
			"println('Prime numbers <= ' + $maxPrime)",
			"println('2')",
			"$n = 3",
			"REPEAT",
			"  $rootN = int(sqrt($n))",
			"  $notPrime = false",
			"  $i = 3",
			"  WHILE($i <= $rootN && NOT($notPrime))",
			"    $notPrime = ($n % $i == 0)",
			"    $i = $i + 1",
			"  WEND",
			"  IF($notPrime == false)",
			"    println($n)",
			"  ENDIF",
			"  $n = $n + 2",
			"UNTIL($n > $maxPrime)"
	};

	String[] m10 = new String[]{
			"c0 = C(2,4); c1 = C(8, 16)",
			"d0 = 0.5",
			"println( c0 * c1)",
			"println( c0 * d0)",
			"println( d0 * c1)",
			"println( runtime() )",
			"END(0)"
	};
	String[] m11 = new String[]{
			"c0 = 4; c1 =24",
			"d0 = 0.5",
			"println( c0 / c1)",
			"println( c0 / d0)",
			"println( d0 / c1)",
			"println( runtime() )",
			"END(0)"
	};


	@EventHandler
	public void onScriptEvent(ScriptEvent event) {
		//System.out.println("Event: " + event.getClass().getSimpleName());

		if (event instanceof TraceEvent) {

		} else if (event instanceof SyntaxErrorEvent) {
			System.out.println(event.getMessage());
		} else if (event instanceof EvaluationErrorEvent) {

		} else if (event instanceof HaltExecutionEvent) {

		} else if (event instanceof ScriptFinishedEvent) {

		} else if (event instanceof OutputEvent) {

		} else if (event instanceof StoreUpdateEvent) {

		} else if (event instanceof WaitEvent) {

		} else if (event instanceof ResumeEvent) {

		}
	}

	void printTokens(String title, List<Token> tokens){
		System.out.println("-------------------------------------------------------------------");
		System.out.println(title);
		System.out.println("Line    Pos     Width   Token");
		for(Token token : tokens){
			System.out.println(token.getLine() + "\t" + token.getCharStart() + "\t" + token.getCharWidth() + "\t" + token.forListing());
		}
		System.out.println("-------------------------------------------------------------------");
	}

	public static void main(String[] args) {
		Test that = new Test();
		that.run();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("\nPROGRAM EXIT");
		System.exit(0);
	}
}
